package com.tjx.service.impl;

import com.tjx.entity.Coupon;
import com.tjx.entity.CouponUser;
import com.tjx.mapper.CouponMapper;
import com.tjx.mapper.CouponUserMapper;
import com.tjx.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tjx.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.Map;

/**
 * <p>
 * 优惠券表 服务实现类
 * </p>
 *
 * @author tjx
 * @since 2025-10-29
 */
@Service
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {
    @Autowired
    private CouponMapper couponMapper;
    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private CouponUserMapper couponUserMapper;

    /**
     * 查询优惠券详情
     */
    @Override
    public Coupon couponQueryDetail(Coupon coupon) {
        if (coupon.getCouponId() == null) {
            throw new IllegalArgumentException("优惠券ID不能为空");
        }
        // 使用QueryWrapper根据业务ID查询，而不是selectById
        Coupon couponDetail = couponMapper.selectOne(
                new QueryWrapper<Coupon>().eq("coupon_id", coupon.getCouponId())
        );
        if (couponDetail == null) {
            throw new IllegalArgumentException("优惠券不存在");
        }
        return couponDetail;
    }

    /**
     * 优惠卷预热新增优惠券
     */
    @Override
    public void couponPreheatAdd(Coupon coupon) {
        if (coupon.getCouponId() == null) {
            throw new IllegalArgumentException("优惠券ID不能为空");
        }

        // 使用QueryWrapper根据业务ID查询，而不是selectById
        Coupon couponDetail = couponMapper.selectOne(
                new QueryWrapper<Coupon>().eq("coupon_id", coupon.getCouponId())
        );
        if (couponDetail == null) {
            throw new IllegalArgumentException("优惠券不存在");
        }
        // 设置缓存
        redisUtils.set("coupon:stock:" + coupon.getCouponId(), couponDetail.getRemainingStock());
        // 修复Redis键名和存储方式
        try {
            redisUtils.hsetAll("coupon:info:" + coupon.getCouponId(), redisUtils.convertToMap(couponDetail));
        } catch (IllegalAccessException e) {
            throw new RuntimeException("优惠券信息转换失败", e);
        }
    }

    /**
     * 领取优惠券（修正后：标准乐观锁实现）
     */
    @Transactional
    @Override
    public boolean couponDeductStock(String couponId, String userId) {
        if (couponId == null || userId == null) {
            throw new IllegalArgumentException("优惠券ID和用户ID不能为空");
        }
        LocalDate currentDate = LocalDate.now();

        // 1. Redis前置校验：优惠券信息、过期时间、重复领取、库存
        Map<Object, Object> couponInfo = redisUtils.hgetAll("coupon:info:" + couponId);
        if (couponInfo == null || couponInfo.isEmpty()) {
            throw new IllegalArgumentException("优惠券信息不存在或已失效");
        }
        // 过期时间校验（已修复类型转换问题，无需修改）
        LocalDate expirationTime = null;
        Object expTimeObj = couponInfo.get("expirationTime");
        if (expTimeObj != null) {
            if (expTimeObj instanceof LocalDate) {
                expirationTime = (LocalDate) expTimeObj;
            } else if (expTimeObj instanceof String) {
                try {
                    expirationTime = LocalDate.parse((String) expTimeObj);
                } catch (DateTimeParseException e) {
                    throw new IllegalArgumentException("优惠券过期时间格式错误");
                }
            } else {
                throw new IllegalArgumentException("优惠券过期时间类型不支持");
            }
        }
        if (expirationTime == null || expirationTime.isBefore(currentDate)) {
            throw new IllegalArgumentException("优惠券已过期");
        }

        // 缓存库存校验
        Integer remainingStock = (Integer) redisUtils.get("coupon:stock:" + couponId);
        if (remainingStock == null || remainingStock <= 0) {
            throw new IllegalArgumentException("优惠券库存不足");
        }

        // 防重复领取：用Redis Set的sismember校验
        boolean isFirstReceive = redisUtils.sadd("coupon:user:" + couponId, userId);
        if (!isFirstReceive) { // sadd 返回 false → 已领取，拦截
            throw new IllegalArgumentException("用户已拥有该优惠券");
        }

        // 2. 扣减缓存库存（前置拦截高并发）
        remainingStock--;
        redisUtils.set("coupon:stock:" + couponId, remainingStock);

        // 3. 数据库乐观锁校验+更新（核心步骤）
        // 3.1 按业务ID查询数据库最新信息（含旧版本号），避免selectById查询失败
        Coupon dbCoupon = couponMapper.selectOne(
                new QueryWrapper<Coupon>().eq("coupon_id", couponId)
        );
        if (dbCoupon == null || dbCoupon.getRemainingStock() <= 0) {
            // 库存不足，回滚缓存
            redisUtils.set("coupon:stock:" + couponId, remainingStock + 1);
            throw new IllegalArgumentException("优惠券库存不足");
        }
        Integer oldVersion = dbCoupon.getVersion(); // 获取数据库旧版本号（如 0）

        // 3.2 执行乐观锁更新：传入旧版本号，由SQL校验并自增
        int row = couponMapper.couponDeductStock(couponId, oldVersion);
        if (row == 0) {
            // 影响行数=0 → 版本冲突（数据已被其他线程修改），回滚缓存
            redisUtils.set("coupon:stock:" + couponId, remainingStock + 1);
            throw new IllegalArgumentException("优惠券领取失败，请重试");
        }

        // 4. 同步更新Redis中的版本号（可选，优化后续缓存查询）
        redisUtils.hset("coupon:info:" + couponId, "version", oldVersion + 1);

        // 5. 记录用户领取记录（入库+Redis Set）
        CouponUser couponUser = new CouponUser();
        couponUser.setUserId(userId);
        couponUser.setCouponId(couponId);
        couponUser.setCouponCode("couponCode_" + couponId + "_" + userId); // 生成唯一优惠券码（避免重复）
        couponUserMapper.insert(couponUser);

        // 6. 标记用户已领取（Redis Set自动去重）
        return redisUtils.sadd("coupon:user:" + couponId, userId);
    }

    /**
     * 查询优惠券列表
     */
    @Override
    public List<Coupon> getCouponList() {
        return couponMapper.selectList(null);
    }

    /**
     * 新增优惠券
     */
    @Override
    public Integer addCoupon(Coupon coupon) {
        coupon.setRemainingStock(coupon.getTotalStock());
        coupon.setCreateDate(LocalDate.now());
        coupon.setUpdateDate(LocalDate.now());
        coupon.setIsDeleted(0);
        Integer row1 = couponMapper.insert(coupon);
        if (row1 > 0) {
            coupon.setCouponId("coupon" + coupon.getId());
            Integer row2 = couponMapper.updateById(coupon);
            if (row2 > 0) {
                return row2;
            }
        }
        return row1;
    }

    /**
     * 更新优惠券
     */
    @Override
    public Integer updateCoupon(Coupon coupon) {
        coupon.setUpdateDate(LocalDate.now());
        return couponMapper.updateById(coupon);
    }

    /**
     * 删除优惠券
     */
    @Override
    public Integer deleteCoupon(Coupon coupon) {
        coupon.setIsDeleted(1);
        coupon.setUpdateDate(LocalDate.now());
        return couponMapper.updateById(coupon);
    }

}